home *** CD-ROM | disk | FTP | other *** search
- /*
- * Get input string, with VMS-style input line editing
- * and previous-command scrolling.
- *
- * Written for Turbo C 2.0 / Borland C++ 2.0
- * Bob Bybee, 2/91
- */
- #include <stdio.h>
- #include <string.h>
-
- /* ASCII key definitions */
- #define ESC_KEY 0x1b
- #define DELETE_KEY 0x7f
- #define BACKSPACE_KEY 0x08
- #define RETURN_KEY 0x0d
- #define CTRL(x) ((x) & 0x1f)
-
- /* Arbitrary values for tracking cursor key entry.
- * These happen to match PC BIOS scan codes, but any
- * unique values would work.
- */
- #define UP_ARROW 0x4800
- #define DOWN_ARROW 0x5000
- #define RIGHT_ARROW 0x4d00
- #define LEFT_ARROW 0x4b00
-
- /* MAX_RECALL is two greater than the number of lines
- * we want in the "lastlines" recall buffer.
- */
- #define MAX_RECALL 22
- #define RECSUB(x) (((x) + MAX_RECALL) % MAX_RECALL)
- #define RECALL_LEN 100
- static char lastlines[MAX_RECALL][RECALL_LEN];
-
- static int num_got; /* # chars in input buffer */
- static int cursor_pos; /* cursor position on line */
- static int lastptr = 0; /* ptr to last line entered */
- static char erase_one[] = "\b \b"; /* erase one character */
- static char *str_ptr; /* ptr to current input string */
-
-
- /* prototypes for this file */
- static void clear_line( void );
- static int cursor_right( void );
- static int cursor_left( void );
- static int get_char_esc( void );
- static void put_str( char *str );
-
- /* external functions (see listing2.c) */
- void sys_putchar( char ch );
- int sys_getchar( void );
-
-
-
- /*
- * get_str() is called by main() to get a line of input.
- * The input line is placed in "str" and will be no
- * more than "len" characters.
- */
- void get_str( char *str, int len )
- {
- int i, c, curptr, insert_mode = 1;
-
- num_got = 0;
- cursor_pos = 0;
- str_ptr = str; /* copy the buffer pointer */
- curptr = RECSUB(lastptr + 1);
- lastlines[curptr][0] = '\0';
- lastlines[RECSUB(curptr + 1)][0] = '\0';
- if (len > RECALL_LEN - 1) /* limit len to RECALL_LEN */
- len = RECALL_LEN - 1;
-
- while (1)
- {
- c = get_char_esc();
-
- if (c == RETURN_KEY)
- break;
- else if (c == DELETE_KEY || c == BACKSPACE_KEY)
- {
- if (cursor_left())
- {
- ++cursor_pos;
- for (i = cursor_pos; i < num_got; ++i)
- {
- str[i - 1] = str[i];
- sys_putchar(str[i]);
- }
- sys_putchar(' ');
- for (i = cursor_pos; i <= num_got; ++i)
- sys_putchar('\b');
- --num_got;
- --cursor_pos;
- }
- }
- else if (c == CTRL('X')) /* erase line? */
- clear_line();
- else if (c == CTRL('A')) /* insert/overtype? */
- insert_mode ^= 1;
- else if (c == CTRL('B')) /* beginning-of-line? */
- {
- while (cursor_left())
- ;
- }
- else if (c == CTRL('E')) /* end-of-line? */
- {
- while (cursor_right())
- ;
- }
- else if (c == CTRL('R')) /* recall last line? */
- {
- clear_line();
- strcpy(str, lastlines[lastptr]);
- if ((num_got = strlen(str)) > 0)
- {
- put_str(str);
- break;
- }
- }
- else if (c == UP_ARROW)
- {
- clear_line();
- if (lastlines[curptr][0] != '\0' ||
- lastlines[RECSUB(curptr - 1)][0] != '\0')
- {
- curptr = RECSUB(curptr - 1);
- strcpy(str, lastlines[curptr]);
- put_str(str);
- cursor_pos = num_got = strlen(str);
- }
- }
- else if (c == DOWN_ARROW)
- {
- clear_line();
- if (lastlines[curptr][0] != '\0' ||
- lastlines[RECSUB(curptr + 1)][0] != '\0')
- {
- curptr = RECSUB(curptr + 1);
- strcpy(str, lastlines[curptr]);
- put_str(str);
- cursor_pos = num_got = strlen(str);
- }
- }
- else if (c == LEFT_ARROW)
- {
- if (cursor_pos > 0)
- {
- sys_putchar('\b');
- --cursor_pos;
- }
- }
- else if (c == RIGHT_ARROW)
- cursor_right();
- else if (' ' <= c && c < 0x7f && num_got < len - 1)
- {
- if (insert_mode)
- {
- /* Move right, all the characters
- * to the right of cursor_pos.
- */
- for (i = num_got; i > cursor_pos; --i)
- str[i] = str[i - 1];
- str[cursor_pos] = c;
- for (i = cursor_pos; i <= num_got; ++i)
- sys_putchar(str[i]);
- for (i = cursor_pos; i < num_got; ++i)
- sys_putchar('\b');
- ++num_got;
- ++cursor_pos;
- }
- else /* insert is off, use overtype mode */
- {
- str[cursor_pos] = c;
- sys_putchar(c);
- if (cursor_pos == num_got)
- ++num_got;
- ++cursor_pos;
- }
- }
- }
-
- str[num_got] = '\0';
- sys_putchar('\n');
-
- /* If this line is non-empty, and different
- * from the last one accepted, store it into
- * the recall buffer.
- */
- if (num_got > 0 && strcmp(str, lastlines[lastptr]) != 0)
- {
- lastptr = RECSUB(lastptr + 1);
- strcpy(lastlines[lastptr], str);
- }
- }
-
-
- /*
- * Move the cursor right one position, by echoing the
- * character it's currently over.
- * Return 1-OK, 0-can't move.
- */
- static int cursor_right( void )
- {
- if (cursor_pos < num_got)
- {
- sys_putchar(str_ptr[cursor_pos]);
- ++cursor_pos;
- return (1);
- }
- return (0);
- }
-
-
- /*
- * Move the cursor left one position, by echoing
- * a backspace. Return 1-OK, 0-can't move.
- */
- static int cursor_left( void )
- {
- if (cursor_pos > 0)
- {
- sys_putchar('\b');
- --cursor_pos;
- return (1);
- }
- return (0);
- }
-
-
- /*
- * Erase all characters on the current line.
- */
- static void clear_line( void )
- {
-
- while (cursor_right())
- ; /* move right, to end of line */
-
- cursor_pos = 0;
- while (num_got > 0)
- {
- put_str(erase_one); /* then, erase to left */
- --num_got;
- }
- }
-
-
- /*
- * Get a character, with escape processing.
- * Handles special sequences like "ESC [ A" for up-arrow.
- * This function would need to be modified to handle
- * keyboards that are neither PC's nor VT-100's.
- */
- static int get_char_esc( void )
- {
- int ch;
-
- ch = sys_getchar();
- if (ch != ESC_KEY)
- return (ch);
-
- ch = sys_getchar();
- if (ch != '[')
- return (ch);
-
- ch = sys_getchar();
- if (ch == 'A')
- return (UP_ARROW); /* was ESC [ A */
- else if (ch == 'B')
- return (DOWN_ARROW); /* was ESC [ B */
- else if (ch == 'C')
- return (RIGHT_ARROW); /* was ESC [ C */
- else if (ch == 'D')
- return (LEFT_ARROW); /* was ESC [ D */
- else
- return (ch);
- }
-
-
- /*
- * Put a string to sys_putchar().
- */
- static void put_str( char *str )
- {
- while (*str != '\0')
- sys_putchar(*str++);
- }
-